using IQIGame.Onigao.Framework;
using Unity.Collections;
using UnityEngine;
#if !UNITY_EDITOR
using System.Reflection;
using HybridCLR;
using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using System.IO;
using System;
#endif

namespace IQIGame.Onigao.GameAOT
{
    public class GameLauncher : MonoBehaviour
    {
#if UNITY_EDITOR
        private void Start()
#else
        private async void Start()
#endif
        {
            System.Globalization.CultureInfo.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
            FrameworkEntry.Instance.Init();
            //TODO 用钩子方式，判断用户目录如有procedure的dll，就优先执行该dll，否则使用aot的procedure

            //目前因为要开发热更逻辑, 所以简单实现了热更自己HotUpdateAssembly, 需要热更后重启才会生效, 后续考虑直接HotUpdateAssembly进行aot.
#if UNITY_EDITOR
            if (!HybridCLRUtil.HybridCLREditActive)
            {
                //编辑器反射调用dll
                ReflectionUtility.CallStaticMethod("HotUpdateAssembly.dll", "IQIGame.Onigao.HotUpdate.HotUpdateEntry", "Init");
            }
#else
            var aotmetadataAb = await LoadABUtility.LoadAb("bundles/res/10_dlls/aotmetadata.ab");
            TextAsset fileListBinary = aotmetadataAb.LoadAsset<TextAsset>("Assets/" + HybridCLRUtil.CodeDllPath + HybridCLRUtil.AOTMetadataPath + "/" + HybridCLRUtil.AotFileListName);
            
            if (fileListBinary == null || fileListBinary.bytes == null)
            {
                Debug.LogError("LoadMetadataForAOTAssemblies FileList failed:" + HybridCLRUtil.AotFileListName);
                return;
            }
            List<string> aotFileList = new List<string>();
            try
            {
                using (MemoryStream ms = new MemoryStream(fileListBinary.bytes))
                using (BinaryReader br = new BinaryReader(ms))
                {
                    var count = br.ReadInt32();
                    for (int i = 0; i < count; i++)
                    {
                        aotFileList.Add(br.ReadString());
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogError($"Read AotFileList[{HybridCLRUtil.AotFileListName}] failed:{ex}");
            }

            HomologousImageMode mode = HomologousImageMode.SuperSet;
            foreach (var aotDllName in aotFileList)
            {
                //byte[] dllBytes = BetterStreamingAssets.ReadAllBytes(aotDllName + ".bytes");
                var text = aotmetadataAb.LoadAsset<TextAsset>("Assets/" + HybridCLRUtil.CodeDllPath + HybridCLRUtil.AOTMetadataPath + "/" + aotDllName);
                if (text == null)
                {
                    return;
                }
                byte[] dllBytes = text.bytes;
                // 加载assembly对应的dll，会自动为它hook。一旦aot泛型函数的native函数不存在，用解释器版本代码
                LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
                Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
            }
            aotmetadataAb.Unload(false);

            AssetBundle assetBundle = await LoadABUtility.LoadAb("bundles/res/10_dlls.ab");
            TextAsset textAsset = assetBundle.LoadAsset<TextAsset>("Assets/" + HybridCLRUtil.CodeDllPath + "HotUpdateAssembly.dll.bytes");
            assetBundle.Unload(false);
            Assembly hotUpdateAssembly = Assembly.Load(textAsset.bytes);
            if (hotUpdateAssembly == null)
            {
                LogGame.LogError("load HotUpdate Assembly failed!");
                return;
            }
            var t = hotUpdateAssembly.GetType("IQIGame.Onigao.HotUpdate.HotUpdateEntry");
            if (t != null)
            {
                t.InvokeMember("Init", BindingFlags.InvokeMethod, null, null, null);
                LogGame.Log("Load HotUpdate Assembly Success!");
            }
            else
            {
                LogGame.LogError("Not find type HotUpdateEntry Init");
            }
#endif

            if (FrameworkEntry.Instance.DevMode)
            {
                NativeLeakDetection.Mode = NativeLeakDetectionMode.Enabled;
            }
            else
            {
                NativeLeakDetection.Mode = NativeLeakDetectionMode.Disabled;
            }
            DontDestroyOnLoad(this);

        }
    }
}
